package com.kusiri.kframework.metadata
{
	import com.kusiri.kframework.component.IKfComponent;
	
	import flash.utils.describeType;
	import flash.utils.getDefinitionByName;
	
	/**
	 * The metadata for a given component class
	 */
	public class KfComponentMetadata
	{

		
		/**
		 * 
		 */
		protected var _clazzName : String;
		
		
		/**
		 * 
		 */
		protected var _clazz : Class;
		
		/**
		 * 
		 */
		protected var _clazzDescription : XML;

		/**
		 * 
		 */
		protected var _propertiesProcessed : Boolean = false;

		/**
		 * Array of KfComponentPropertyMetadata
		 */
		protected var _userProperties : Object;
		
		/**
		 * Array of KfComponentPropertyMetadata
		 */
		protected var _userSettableProperties : Array;
		
		/**
		 * Array of KfComponentPropertyMetadata
		 */
		protected var _userGettableProperties : Array;
	
		/**
		 * 
		 */
		public function KfComponentMetadata(  clazz : String )
		{
			_clazzName = clazz;
			_clazz = getDefinitionByName(clazz) as Class;
			_clazzDescription = describeType(_clazz).factory[0];
		}

		/**
		 * 
		 */
		public function get isUiComponent() : Boolean
		{
			return _clazzDescription.implementsInterface.(@type=="com.kusiri.kframework.ui::IKfUiComponent")[0] != null;
		}

		/**
		 * 
		 */
		public function getPropertyMetadata( propertyName : String ) : KfComponentPropertyMetadata
		{
			return properties[propertyName];
		} 

		/**
		 * Returns an array of KfComponentPropertyMetadata
		 */
		public function get settableProperties() : Array
		{
			processProperties();
			return _userSettableProperties;
		}
		
		/**
		 * Returns an array of KfComponentPropertyMetadata
		 */
		public function get gettableProperties() : Array
		{
			processProperties();
			return _userGettableProperties;
		}
			
		/**
		 * Returns an object of KfComponentPropertyMetadata, mapped by name
		 */
		public function get properties() : Object
		{
			processProperties();
			return _userProperties;
		}
		
		/**
		 * 
		 */
		protected function processProperties() : void
		{
//			if ( _propertiesProcessed ) 
//			{
//				return;
//			}			
			
			_propertiesProcessed = true;
			
			_userSettableProperties = [];
			_userGettableProperties = [];
			_userProperties = {};
			
			// List the object's variables, their values, and their types.
            for each (var v:XML in _clazzDescription..variable) 
            {
            	var type : String = v.@type;
            	var name : String = v.@name;
            	var hidden : Boolean = name.charAt(0)=='_';
            	
            	if (hidden) continue;
        		
        		var metadata : KfComponentPropertyMetadata = new KfComponentPropertyMetadata(name, type, camelCaseToNormal(name));
 				
 				_userProperties[name] = metadata;
 				_userSettableProperties.push(metadata);
            	_userGettableProperties.push(metadata);
            }

            // List accessors as properties.
            for each (var a:XML in _clazzDescription..accessor) 
            {
            	var atype : String = a.@type;
            	var aname : String = a.@name;
            	var x = aname.charAt(0);
            	var ahidden : Boolean = aname.charAt(0)=='_';
            	
            	if (ahidden) continue;
            	
            	var acanWrite : Boolean = a.@access != 'readonly';
            	var acanRead : Boolean = a.@access != 'writeonly';
            	
            	var ametadata : KfComponentPropertyMetadata = new KfComponentPropertyMetadata(aname, atype, camelCaseToNormal(aname));
            	_userProperties[aname] = ametadata;
            	
            	if (  acanWrite ) 
            	{
 					_userSettableProperties.push(ametadata);
            	}
            	
            	if (  acanRead ) 
            	{
 					_userGettableProperties.push(ametadata);
            	}
            }  

		}
		
		/**
		 * Convert a camelCase string to a Camel Case string
		 */
		protected function camelCaseToNormal(string : String) : String
		{
			return string.replace(/([A-Z])/g, " $1").replace(/^([a-z])/, function():String {
				var firstLetter : String = arguments[1] as String; 
				return firstLetter.toLocaleUpperCase(); 
			});
		}

		/**
		 * 
		 */
		public function getNewInstance() : IKfComponent
		{
			return new _clazz(); 
		}

	}
}